package com.oj.controller;

import com.oj.entity.Packet;
import com.oj.entity.Solution;
import com.oj.entity.User;
import com.oj.mapper.PacketMapper;
import com.oj.service.UserService;
import com.oj.service.impl.I18nService;
import com.oj.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.imageio.IIOParam;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Controller
@RequestMapping
public class PacketController {
    @Autowired
    private UserService userService;
    @Autowired
    private PacketMapper packetMapper;
    @Autowired
    private I18nService i18nService;
    @RequestMapping(value = {"/packethub"}, method = RequestMethod.GET)
    public ModelAndView toHpd(Model model){
        String hex = "01005e00000ac20173fe0000080045c0003c000000000258cd9f0a000001e000000a0205ee68000000000000000000000000000000640001000c010001000000000f000400080c040102";
        Integer total = packetMapper.count();
        Random random = new Random();
        int id = random.nextInt(total) + 1;
        Packet p = packetMapper.query(id);
        if (p != null) {
            hex = p.getHex();
        }
        ModelAndView mv = new ModelAndView();
        mv.addObject("total", total);
        mv.addObject("hex", hex);
        mv.setViewName("tools/packethub.html");
        return mv;
    }

    @ResponseBody
    @RequestMapping(value = {"/api/packet/decode"})
    public Result apiHpd(String hex, HttpServletRequest request){
        try {
            log.info("hex packet decode.");

            hex = hex.replaceAll(" ", "");

            Packet packet = new Packet();
            User user = userService.getUserBySession(request);
            if (user != null) {
                packet.setUsername(user.getUsername());
            }
            packet.setIp(IpUtil.getIpAddr(request));
            packet.setHex(hex);
            packet.setDate(new Date());

            String pktFmt = "";
            for (int i = 0; i < hex.length(); i++) {
                if (i % 2 == 0) {
                    pktFmt += " ";
                }
                pktFmt += hex.charAt(i);
            }
            pktFmt = pktFmt.trim();

            String pcap = Hex2Pcap.hex2Pcap(pktFmt, null);
            String detail = Hex2Pcap.PacketDumpDetails(pcap);
            Pattern pattern = Pattern.compile(
                    Pattern.quote("[Protocols in frame:") + "(.*?)" + Pattern.quote("]"));
            Matcher matcher = pattern.matcher(detail);
            if (matcher.find()) {
                String proto = matcher.group(1).toString().trim();
                if ("eth:ethertype:data".equals(proto)) {
                    if (pktFmt.startsWith("6")) {
                        pcap = Hex2Pcap.hex2Pcap(pktFmt, "0x86dd");
                    }
                    if (pktFmt.startsWith("4")) {
                        pcap = Hex2Pcap.hex2Pcap(pktFmt , "0x0800");
                    }
                    detail = Hex2Pcap.PacketDumpDetails(pcap);
                    matcher = pattern.matcher(detail);
                    if (matcher.find()) {
                        proto = matcher.group(1).toString().trim();
                    }
                }
                packet.setProtocol(proto);
            }else {
                log.info("proto is null");
                File fileCap = new File(pcap);
                fileCap.delete();
                return Result.error(CodeMsg.PARAM_INVALID.locale());
            }

            String hexDump = Hex2Pcap.PacketDumpHex(pcap);
            String xml = Hex2Pcap.PacketDumpXML(pcap);
            String verbose = Hex2Pcap.PacketDumpVerbose(pcap);
            File fileCap = new File(pcap);
            fileCap.delete();
            packet.setDetail(detail);
            packet.setVerbose(verbose);
            Packet p = packetMapper.queryByHex(hex);
            if (p == null) {
                packetMapper.insert(packet);
            } else {
                if (p.getUsername() == null && user != null && p.getIp().equals(IpUtil.getIpAddr(request))) {
                    packetMapper.delete(p.getId());
                    packetMapper.insert(packet);
                } else {
                    packet.setId(p.getId());
                    packetMapper.update(packet);
                }
            }

            Integer total = packetMapper.count();
            Map ret = new HashMap();
            ret.put("hexDump", hexDump);
            ret.put("xml", xml);
            ret.put("verbose", verbose);
            ret.put("total", total);
            ret.put("copy", i18nService.getMessage("packet-copy"));
            ret.put("close", i18nService.getMessage("packet-copy-close"));
            return Result.success(ret);
        } catch (Exception e) {
            log.error(e.toString());
            return Result.error(CodeMsg.INNER_FAULT.locale());
        }
    }

    @ResponseBody
    @RequestMapping(value = {"/api/packet/search"}, method = RequestMethod.GET)
    public Result<List> apiPackets(String q, Integer limit, Integer offset, HttpServletRequest request){
        if (limit == null) {
            limit = 0;
        }
        if (offset == null) {
            offset = 0;
        }

        Map param = new HashMap();
        param.put("q", q);
        param.put("limit", limit);
        param.put("offset", offset);
        List<Packet> packets = packetMapper.search(param);
        for (Packet p:packets) {
            p.setFriendlyDate(DateUtil.toFriendlyDate(p.getDate()));

            if (p.getUsername() != null) {
                p.setUser(userService.query(p.getUsername()));
            }
        }
        return Result.success(packets);
    }
}
